package cn.lghuntfor.commons.trace.dubbo;

import cn.hutool.core.util.StrUtil;
import cn.lghuntfor.commons.common.constants.Consts;
import cn.lghuntfor.commons.common.spring.SpringUtils;
import cn.lghuntfor.commons.trace.common.TraceConstant;
import cn.lghuntfor.commons.trace.common.TraceContext;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.Map;

/**
 * dubbo调用链路日志信息获取封装, 服务调用者
 * 基于dubbo spi机制
 * @author liaogang
 * @date 2020/9/10 17:06
 */
@Slf4j
@Activate(group = {CommonConstants.CONSUMER},order = 100000)
public class TraceConsumerDubboFilter implements Filter {

    private String springApplicationName = null;

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String cid = this.getSpringApplicationName();
        String classMethodName = invoker.getInterface().getSimpleName()+"."+invocation.getMethodName();
        addTraceInfo(cid);

        long startTime = System.currentTimeMillis();
        Result result = invoker.invoke(invocation);
        String attachment = getAttachment(invocation);
        log.info("{}, consumer elapsed time = {}ms, attachment={}", classMethodName, (System.currentTimeMillis() - startTime), attachment);
        return result;
    }

    private String getAttachment(Invocation invocation) {
        Map<String, Object> attachmentMap = invocation.getObjectAttachments();
        if (attachmentMap != null) {
            return JSON.toJSONString(attachmentMap);
        }
        return Consts.STR_EMPTY;
    }

    /**
     * 获取信息并传递到dubbo attachment中
     * @author liaogang
     * @date 2020/9/18
     * @param cid
     * @return void
     */
    private void addTraceInfo(String cid) {
        try {
            /** 作为 consumer 端, 传递链路信息 */
            String tid = TraceContext.getTraceId();
            RpcContext.getContext().setAttachment(TraceConstant.TID_KEY, tid);
            RpcContext.getContext().setAttachment(TraceConstant.PID_KEY, cid);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 获取当前应用名
     */
    private String getSpringApplicationName() {
        if (StrUtil.isNotBlank(springApplicationName)) {
            return springApplicationName;
        }
        springApplicationName = SpringUtils.getApplicationName();
        return springApplicationName;
    }
}
